#pragma once
#include "Socket.hpp"
#include <thread>

class tcpServer
{
    static const uint16_t defaultPort = 2025;
    static const size_t maxfd = 128;

public:
    tcpServer(uint16_t port = defaultPort)
        : _listensock(-1), _port(port) {}
    ~tcpServer()
    {
        if (_listensock > 0)
            close(_listensock);
        _listensock = -1;
    }

    // 初始化到监听即可
    void init()
    {
        std::cout << "init start" << std::endl;
        _listensock = mySocket::creatSockfd();
        mySocket::Bind(_listensock, _port);
        mySocket::Listen(_listensock, gbacklog);
        std::cout << "init success" << std::endl;
    }

    void run()
    {
#if 0
        //单一阻塞处理,无法处理并发问题
        while (true)
        {
            std::string clientip;
            uint16_t clientport;

            // accept获取套接字
            int clientsock = mySocket::Accept(_listensock, clientip, clientport);

            // 处理接收的信息，这里直接当作字符串输出。可以使用多进程/多线程/协程等方式处理数据
            char buffer[128] = "";
            while (true)
            {
                int n = Recver(clientsock, buffer, sizeof(buffer));
                std::cout << "接收的信息是:" << buffer << std::endl;

                if (n < 0)
                    break;
                std::string outbuffer = "server echo:";
                outbuffer += buffer;
                send(clientsock, outbuffer.c_str(), sizeof(outbuffer.c_str()), 0);
            }
        }
#elif 0
        // 多线程并发处理连接,对内存和cpu的消耗较大。不建议使用
        while (true)
        {
            std::string clientip;
            uint16_t clientport;

            // accept获取套接字
            int clientsock = mySocket::Accept(_listensock, clientip, clientport);
            std::cout << "thread " << std::endl;
            std::thread t([this, clientsock]()
                          { this->threadHandleTask(clientsock); });
            t.detach();
        }
#else

        // select处理并发连接   select(maxfd, rset, wset, eset, timeout);
        // select相当于一个秘书，帮助我们管理所有的fd。这样一个线程就能管理所有的事件

        // 设置listen监听事件为读取事件,同时设置rfdset集合
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(_listensock, &rfds);
        int maxfd = _listensock;

        int timeout = 1000;
        while (true)
        {
            fd_set rset = rfds; // 更新读事件集合

            // 使用select注册需要关心的 读事件 / 写事件  / 异常事件
            // 注意第一个参数数组下标要+1用于访问最后一位数据，如果timeout为nullptr表示一直等待事件就绪（阻塞等待）
            int nready = select(maxfd + 1, &rset, nullptr, nullptr, nullptr);

            // 如果允许到这里，说明有事件就绪了！需要通过集合判断就绪的事件
            if (FD_ISSET(_listensock, &rset))
            {
                // 说明监听事件就绪了！，可以建立新的连接
                std::string clientip;
                uint16_t clientport;

                // accept获取同于通信新连接套接字
                int clientsock = mySocket::Accept(_listensock, clientip, clientport);

                // 此时需要关心clientsock这个事件fd！需要加入到rset中，并且更新最大fd用于遍历
                FD_SET(clientsock, &rfds);
                maxfd = clientsock;
            }

            // 遍历rfd中所有的读事件就绪并且处理,由于事件就绪通知我。我直接读数据并且发送即可
            // 直接遍历rfds是肯定会遍历到没有就绪的事件的，如果想要略过非就绪事件，需要自定义结构体处理

            for (int i = _listensock + 1; i <= maxfd; i++)
            {
                if (FD_ISSET(i, &rset))
                {
                    // 处理读就绪事件，首先接收数据存储在buffer中
                    // 处理并向客户端返回处理后的数据

                    char buffer[256] = "";
                    int n = selectHandleTask(i); // 在selectHandleTask中模拟上面两个步骤
                    if (n == 0)
                    {
                        // 数据发送完毕了！对方退出了
                        std::cout << "client quit 需要处理rfd" << std::endl;

                        // 注意处理事件就绪集合rfd
                        FD_CLR(i, &rfds);
                    }
                }
            }
        }
#endif
    }

private:
    size_t Recver(int clientsock, char *buffer, size_t length)
    {
        assert(buffer != nullptr);
        memset(buffer, 0, sizeof(buffer));
        ssize_t n = recv(clientsock, buffer, length - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "recv success" << std::endl;
        }
        else if (n == 0)
        {
            close(clientsock);
            std::cout << "client quit" << std::endl;
        }
        else
        {
            close(clientsock);
            std::cout << "recv error" << std::endl;
            return -1;
        }

        return n;
    }

    // 多线程简易处理信息并且返回
    void threadHandleTask(int clientsock)
    {
        // 处理接收的信息，这里直接当作字符串输出。可以使用多进程/多线程/协程等方式处理数据
        char buffer[128] = "";
        while (true)
        {
            int n = Recver(clientsock, buffer, sizeof(buffer));
            std::cout << "接收的信息是:" << buffer << std::endl;

            if (n < 0)
                break;
            std::string outbuffer = "server echo:";
            outbuffer += buffer;
            std::cout << "发送的信息是:" << outbuffer << std::endl;

            // 注意数据长度不可以使用sizeof，这个长度是一个指针
            send(clientsock, outbuffer.c_str(), strlen(outbuffer.c_str()), 0);
        }
    }

    // select多路复用简易处理信息并且返回，无需循环recv并send。事件就绪我处理发送即可
    int selectHandleTask(int clientsock)
    {
        // // 处理接收的信息，这里直接当作字符串输出。可以使用多进程/多线程/协程等方式处理数据
        // char buffer[128] = "";

        // int n = Recver(clientsock, buffer, sizeof(buffer));
        // std::cout << "接收的信息是:" << buffer << std::endl;

        // if (n == 0)
        //     return 0;
        // else if (n < 0)
        //     exit(-1);
        // else
        // {
        //     std::string outbuffer = "server echo:";
        //     outbuffer += buffer;
        //     std::cout << "发送的信息是:" << outbuffer << std::endl;

        //     // 注意数据长度不可以使用sizeof，这个长度是一个指针
        //     send(clientsock, outbuffer.c_str(), strlen(outbuffer.c_str()), 0);
        // }
        // return n;

        int n;

        std::string body = "<h1>hello world</h1>";
        std::string outbuffer;
        char inbuffer[1024];

        n = Recver(clientsock, inbuffer, sizeof(inbuffer));
        memset(inbuffer, 0, sizeof(inbuffer));

        outbuffer =
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html; charset=utf-8\r\n"
            "Content-Length: " +
            std::to_string(body.size()) + "\r\n"
                                          "Server: Apache/2.4.41\r\n"
                                          "Date: Mon, 18 Dec 2023 08:32:10 GMT\r\n"
                                          "X-Frame-Options: DENY\r\n"
                                          "X-Content-Type-Options: nosniff\r\n"
                                          "Referrer-Policy: strict-origin-when-cross-origin\r\n"
                                          "\r\n" // 空行分隔头部和正文
            + body;
        int count = send(clientsock, outbuffer.c_str(), outbuffer.size(), 0);
        if (count == 0)
            close(clientsock);
        return n;
    }

private:
    int _listensock;
    std::string _ip;
    uint16_t _port;
};